﻿namespace Flash.Web.UI
{
    using Extensions.Linq;
    using Extensions.Web.UI;
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Threading;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    public class UserControl : UserControl
    {
        private Circumscription _circumscription = null;
        private HttpContext _context = HttpContext.Current;
        private FlashEventArgs _eventArg = null;
        private System.Web.UI.Page _page = null;
        private static Setter<System.Web.UI.Page, HttpApplicationState> applicationSetter = new ComponentOperator().GetFieldSetter<System.Web.UI.Page, HttpApplicationState>("_application");
        private static Setter<System.Web.UI.Page, Cache> cacheSetter = new ComponentOperator().GetFieldSetter<System.Web.UI.Page, Cache>("_cache");
        private static Setter<System.Web.UI.Page, HttpContext> contextSetter = new ComponentOperator().GetFieldSetter<System.Web.UI.Page, HttpContext>("_context");
        private EventHandler Create;
        protected FlashListenCollection Listen;
        private static LoadViewStateExtension LoadViewStateExtensionMethod = new ComponentOperator().ConvertToExtensionMethod<Control, LoadViewStateExtension>("LoadViewState", new Type[] { typeof(object) }, BindingFlags.NonPublic | BindingFlags.Instance);
        private static SaveViewStateExtension SaveViewStateExtensionMethod = new ComponentOperator().ConvertToExtensionMethod<Control, SaveViewStateExtension>("SaveViewState", null, BindingFlags.NonPublic | BindingFlags.Instance);
        private static Getter<Control, StateBag> ViewStateGetter = new ComponentOperator().GetPropertyGetter<Control, StateBag>("ViewState");

        public event EventHandler Create
        {
            add
            {
                EventHandler handler2;
                EventHandler create = this.Create;
                do
                {
                    handler2 = create;
                    EventHandler handler3 = (EventHandler) Delegate.Combine(handler2, value);
                    create = Interlocked.CompareExchange<EventHandler>(ref this.Create, handler3, handler2);
                }
                while (create != handler2);
            }
            remove
            {
                EventHandler handler2;
                EventHandler create = this.Create;
                do
                {
                    handler2 = create;
                    EventHandler handler3 = (EventHandler) Delegate.Remove(handler2, value);
                    create = Interlocked.CompareExchange<EventHandler>(ref this.Create, handler3, handler2);
                }
                while (create != handler2);
            }
        }

        protected void ChildControlCreate(Control control, Dictionary<string, object> value, bool isBind)
        {
            foreach (Control control2 in control.Controls)
            {
                bool flag = isBind;
                if (control2 is UserControl)
                {
                    UserControl control3 = (UserControl) control2;
                    if (control3.RemoteID != this.RemoteID)
                    {
                        control3.SetRemoteID(this.RemoteID);
                        control3.InitEventArg("$Create", value);
                        control3.CreateControl();
                        flag = true;
                    }
                }
                else if (isBind && (control2 is BaseDataBoundControl))
                {
                    EnsureControlDataBound((BaseDataBoundControl) control2);
                    flag = false;
                }
                else if (isBind && (control2 is BaseDataList))
                {
                    EnsureControlDataBound((BaseDataList) control2);
                    flag = false;
                }
                this.ChildControlCreate(control2, value, flag);
            }
        }

        protected void ChildControlListen(Control control, string name, Dictionary<string, object> value)
        {
            try
            {
                foreach (Control control2 in control.Controls)
                {
                    this.ChildControlListen(control2, name, value);
                    if (control2 is UserControl)
                    {
                        UserControl control3 = (UserControl) control2;
                        if (control3.RemoteID == this.RemoteID)
                        {
                            control3.InitEventArg(name, value);
                            if (name == "$Create")
                            {
                                control3.CreateControl();
                            }
                            else if ((control3.Listen != null) && control3.Listen.Contains(name))
                            {
                                control3.Listen.GetListen(name).ExecuteListen(control3._eventArg);
                            }
                        }
                    }
                }
            }
            catch (InvalidOperationException)
            {
                this.ChildControlListen(control, name, value);
            }
        }

        protected void ChildControlRender(Control control, string name, Dictionary<string, object> value)
        {
            foreach (Control control2 in control.Controls)
            {
                this.ChildControlRender(control2, name, value);
                if (control2 is UserControl)
                {
                    UserControl control3 = (UserControl) control2;
                    if (control3.RemoteID == this.RemoteID)
                    {
                        control3.InitEventArg(name, value);
                        control3.OnRender(control3._eventArg);
                    }
                    else
                    {
                        control3.SetRemoteID(this.RemoteID);
                        control3.InitEventArg("$Create", value);
                        control3.CreateControl();
                        control3.InitEventArg(name, value);
                        control3.OnRender(control3._eventArg);
                    }
                }
            }
        }

        private void CreateControl()
        {
            this.Listen = new FlashListenCollection(this);
            if (this.FormID == "")
            {
                this.FormID = FindContainerFormID(this);
            }
            this._circumscription.BeginRecord();
            this.OnCreate(this._eventArg);
            this._circumscription.EndRecord();
            this.OnLoad(this._eventArg);
        }

        private System.Web.UI.Page CreateIntrinsicPage()
        {
            System.Web.UI.Page page = new System.Web.UI.Page();
            base.ComponentOperator.SetField<System.Web.UI.Page, HttpContext>(page, contextSetter, this._context);
            base.ComponentOperator.SetField<System.Web.UI.Page, HttpApplicationState>(page, applicationSetter, this._context.Application);
            base.ComponentOperator.SetField<System.Web.UI.Page, Cache>(page, cacheSetter, this._context.Cache);
            return page;
        }

        private static void EnsureControlDataBound(BaseDataBoundControl control)
        {
            try
            {
                if (control.DataSourceID.Length > 0)
                {
                    control.DataBind();
                }
            }
            catch
            {
            }
        }

        private static void EnsureControlDataBound(BaseDataList control)
        {
            try
            {
                if (control.DataSourceID.Length > 0)
                {
                    control.DataBind();
                }
            }
            catch
            {
            }
        }

        private static string FindContainerFormID(Control control)
        {
            Control namingContainer = control;
            string formID = "";
            if (control != control.Page)
            {
                while ((formID == "") && (namingContainer != control.Page))
                {
                    namingContainer = namingContainer.NamingContainer;
                    if (namingContainer == null)
                    {
                        return "";
                    }
                    if (namingContainer is UserControl)
                    {
                        formID = ((UserControl) namingContainer).FormID;
                    }
                }
                return formID;
            }
            return "";
        }

        private string GetListenName(string name)
        {
            if (this.FormID != "")
            {
                return (this.FormID + "$" + name);
            }
            return name;
        }

        internal void InitEventArg(string name, Dictionary<string, object> value)
        {
            if (this._eventArg == null)
            {
                this._eventArg = new FlashEventArgs(this, name, value);
            }
            if (this._circumscription == null)
            {
                this._circumscription = new Circumscription(this);
            }
        }

        internal Dictionary<string, object> ListenEvent(string name, Dictionary<string, object> value)
        {
            this.ChildControlListen(this, name, value);
            this.InitEventArg(name, value);
            bool isBind = name == "$Create";
            if (isBind)
            {
                this.CreateControl();
            }
            else if (this.Listen.Contains(name))
            {
                this.Listen.GetListen(name).ExecuteListen(this._eventArg);
            }
            this.ChildControlCreate(this, value, isBind);
            this.ChildControlRender(this, name, value);
            this.OnRender(this._eventArg);
            return value;
        }

        private static void LoadChildViewState(Control control, Pair state, string name, Dictionary<string, object> value, bool isBind)
        {
            UserControl control2 = null;
            if (control is UserControl)
            {
                control2 = (UserControl) control;
                control2.Listen = new FlashListenCollection(control2);
                control2.LoadListenState();
            }
            if ((state.Second != null) && control.HasControls())
            {
                int num;
                Pair[] second = (Pair[]) state.Second;
                bool[] flagArray = new bool[control.Controls.Count];
                for (num = 0; num < control.Controls.Count; num++)
                {
                    if (isBind)
                    {
                        if (control.Controls[num] is BaseDataBoundControl)
                        {
                            EnsureControlDataBound((BaseDataBoundControl) control.Controls[num]);
                            flagArray[num] = false;
                        }
                        else if (control.Controls[num] is BaseDataList)
                        {
                            EnsureControlDataBound((BaseDataList) control.Controls[num]);
                            flagArray[num] = false;
                        }
                        else
                        {
                            flagArray[num] = true;
                        }
                    }
                    else
                    {
                        flagArray[num] = isBind;
                    }
                    LoadControlViewState(control.Controls[num], second[num].First);
                }
                if (control2 != null)
                {
                    control2.InitEventArg(name, value);
                    control2.OnLoad(control2._eventArg);
                }
                for (num = 0; num < control.Controls.Count; num++)
                {
                    LoadChildViewState(control.Controls[num], second[num], name, value, flagArray[num]);
                }
            }
            else if (control2 != null)
            {
                control2.InitEventArg(name, value);
                control2.OnLoad(control2._eventArg);
            }
        }

        private static void LoadControlViewState(Control control, object savedState)
        {
            if (savedState != null)
            {
                LoadViewStateExtensionMethod(control, savedState);
            }
        }

        internal static void LoadFlashViewState(Control control, Pair state, string name, Dictionary<string, object> value)
        {
            LoadControlViewState(control, state.First);
            LoadChildViewState(control, state, name, value, true);
        }

        private void LoadListenState()
        {
            this.Listen.LoadListenState((Pair[]) this.ViewState["ListenState"]);
        }

        protected virtual void OnCreate(FlashEventArgs e)
        {
            if (this.Create != null)
            {
                this.Create(this, e);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
        }

        protected virtual void OnRender(FlashEventArgs e)
        {
            base.OnPreRender(e);
        }

        private static object SaveControlViewState(Control control)
        {
            if (!string.IsNullOrEmpty(control.ID))
            {
                if (control is UserControl)
                {
                    ((UserControl) control).SaveListenState();
                }
                TrackControlViewState(control);
                return SaveViewStateExtensionMethod(control);
            }
            return null;
        }

        private static Pair SaveFlashViewState(Control control)
        {
            object x = SaveControlViewState(control);
            Pair[] y = null;
            if (control.HasControls())
            {
                y = new Pair[control.Controls.Count];
                for (int i = 0; i < control.Controls.Count; i++)
                {
                    y[i] = SaveFlashViewState(control.Controls[i]);
                }
            }
            return new Pair(x, y);
        }

        private void SaveListenState()
        {
            this.ViewState["ListenState"] = this.Listen.SaveListenState();
        }

        internal void SetRemoteID(string value)
        {
            this.ViewState["__VIEWSTATEGUID"] = value;
        }

        private static void TrackControlViewState(Control control)
        {
            new ComponentOperator().GetProperty<Control, StateBag>(control, ViewStateGetter).SetDirty(true);
        }

        public string WholeUrl(string relativeUrl)
        {
            return (this._context.Request.Url.Scheme + "://" + this._context.Request.Url.Authority + base.ResolveUrl(relativeUrl));
        }

        protected override HttpContext Context
        {
            get
            {
                return this._context;
            }
        }

        internal Pair FlashState
        {
            get
            {
                return SaveFlashViewState(this);
            }
        }

        public string FormID
        {
            get
            {
                return ((this.ViewState["FormID"] != null) ? this.ViewState["FormID"].ToString() : "");
            }
            set
            {
                this.ViewState["FormID"] = value;
            }
        }

        protected FlashEventArgs.FlashValue FormState
        {
            get
            {
                return this._eventArg.Value;
            }
        }

        public override System.Web.UI.Page Page
        {
            get
            {
                if (this._page == null)
                {
                    this._page = this.CreateIntrinsicPage();
                }
                return this._page;
            }
            set
            {
                this._page = value;
            }
        }

        public string RemoteID
        {
            get
            {
                return ((this.ViewState["__VIEWSTATEGUID"] != null) ? this.ViewState["__VIEWSTATEGUID"].ToString() : "");
            }
        }

        public class FlashEventArgs : EventArgs
        {
            private string _name;
            private FlashValue _value;

            public FlashEventArgs(UserControl control, string name, Dictionary<string, object> value)
            {
                this._name = name;
                this._value = new FlashValue(control, value);
            }

            public string Name
            {
                get
                {
                    return this._name;
                }
            }

            public FlashValue Value
            {
                get
                {
                    return this._value;
                }
            }

            public class FlashValue
            {
                private UserControl _control;
                private Dictionary<string, object> _value;

                public FlashValue(UserControl control, Dictionary<string, object> value)
                {
                    this._value = value;
                    this._control = control;
                }

                public object this[string key]
                {
                    get
                    {
                        if (!this._control._circumscription.CheckValueName(key))
                        {
                            throw new FlashValueException(key);
                        }
                        string listenName = this._control.GetListenName(key);
                        if (this._value.ContainsKey(listenName))
                        {
                            return this._value[listenName];
                        }
                        return null;
                    }
                    set
                    {
                        if (!this._control._circumscription.CheckValueName(key))
                        {
                            throw new FlashValueException(key);
                        }
                        if (this._control._circumscription.IsRecording)
                        {
                            this._control._circumscription.RecordValueName(key);
                        }
                        this._value[this._control.GetListenName(key)] = value;
                    }
                }
            }
        }

        public class FlashListen
        {
            private UserControl.OnListen Listen;

            public event UserControl.OnListen Listen
            {
                add
                {
                    UserControl.OnListen listen2;
                    UserControl.OnListen listen = this.Listen;
                    do
                    {
                        listen2 = listen;
                        UserControl.OnListen listen3 = (UserControl.OnListen) Delegate.Combine(listen2, value);
                        listen = Interlocked.CompareExchange<UserControl.OnListen>(ref this.Listen, listen3, listen2);
                    }
                    while (listen != listen2);
                }
                remove
                {
                    UserControl.OnListen listen2;
                    UserControl.OnListen listen = this.Listen;
                    do
                    {
                        listen2 = listen;
                        UserControl.OnListen listen3 = (UserControl.OnListen) Delegate.Remove(listen2, value);
                        listen = Interlocked.CompareExchange<UserControl.OnListen>(ref this.Listen, listen3, listen2);
                    }
                    while (listen != listen2);
                }
            }

            internal void ExecuteListen(UserControl.FlashEventArgs e)
            {
                if (this.Listen != null)
                {
                    this.Listen(e);
                }
            }
        }

        public class FlashListenCollection
        {
            private UserControl _control;
            private Dictionary<string, UserControl.FlashListen> _events = new Dictionary<string, UserControl.FlashListen>();
            private static Getter<UserControl.FlashListen, UserControl.OnListen> listenFieldInfo = new ComponentOperator().GetFieldGetter<UserControl.FlashListen, UserControl.OnListen>("Listen");

            public FlashListenCollection(UserControl control)
            {
                this._control = control;
            }

            internal bool Contains(string name)
            {
                return (this._events.ContainsKey(name) && (this._events[name] != null));
            }

            internal UserControl.FlashListen GetListen(string name)
            {
                return this._events[name];
            }

            private static string[] GetListenMethodNames(UserControl.FlashListen listen)
            {
                string[] strArray = null;
                Delegate field = new ComponentOperator().GetField<UserControl.FlashListen, UserControl.OnListen>(listen, listenFieldInfo);
                if (field != null)
                {
                    Delegate[] invocationList = field.GetInvocationList();
                    strArray = new string[invocationList.Length];
                    for (int i = 0; i < invocationList.Length; i++)
                    {
                        strArray[i] = invocationList[i].Method.Name;
                    }
                }
                return strArray;
            }

            internal void LoadListenState(Pair[] savedState)
            {
                if (savedState != null)
                {
                    Pair[] pairArray = savedState;
                    foreach (Pair pair in pairArray)
                    {
                        if (pair.Second != null)
                        {
                            string[] second = (string[]) pair.Second;
                            this._events.Add(pair.First.ToString(), new UserControl.FlashListen());
                            foreach (string str in second)
                            {
                                MethodInfo method = this._control.GetType().GetMethod(str, BindingFlags.NonPublic | BindingFlags.Instance);
                                if (method != null)
                                {
                                    this._events[pair.First.ToString()].Listen += ((UserControl.OnListen) Delegate.CreateDelegate(typeof(UserControl.OnListen), this._control, method));
                                }
                            }
                        }
                    }
                }
            }

            internal Pair[] SaveListenState()
            {
                Pair[] pairArray = null;
                if (this._events.Count > 0)
                {
                    pairArray = new Pair[this._events.Count];
                    int index = 0;
                    foreach (KeyValuePair<string, UserControl.FlashListen> pair in this._events)
                    {
                        pairArray[index] = new Pair(pair.Key, GetListenMethodNames(pair.Value));
                        index++;
                    }
                }
                return pairArray;
            }

            public UserControl.FlashListen this[string name]
            {
                get
                {
                    if (!(this._events.ContainsKey(this._control.GetListenName(name)) && (this._events[this._control.GetListenName(name)] != null)))
                    {
                        this._events[this._control.GetListenName(name)] = new UserControl.FlashListen();
                    }
                    return this._events[this._control.GetListenName(name)];
                }
            }
        }

        private delegate void LoadViewStateExtension(Control control, object savedState);

        public delegate void OnListen(UserControl.FlashEventArgs e);

        private delegate object SaveViewStateExtension(Control control);
    }
}

